#include <all_lib.h>
#pragma hdrstop

DWORD nPair = 1;
DWORD nLen  = 1;
DWORD nOff  = 0;
BYTE  buff[ 512 ];
DWORD fOff  = 0;
CONSTSTR m;

BYTE ToByte( char b ) {
  if ( b >= 'a' ) return 10 + b - 'a';
  if ( b >= 'A' ) return 10 + b - 'A';
 return b - '0';
}

DWORD Text2BytesRaw( CONSTSTR m, LPBYTE b, DWORD bsz )
  {  DWORD n = 0;

     for( ; bsz && *m; ) {
       while( *m ) {
         if ( strchr("\n\r\t\b ", *m ) != NULL ) m++; else
         if ( strchr("0123456789ABCDEFabcdef", *m ) == NULL ) m++; else
           break;
       }

       if ( !m[0] || !m[1] ) break;

       *b = (ToByte(m[0]) << 4) | ToByte(m[1]);
       m += 2;
       bsz--;
       b++;
       n++;
     }

 return n;
}

void PByte( BYTE b )
  {
      for( DWORD v = 1; (v&0xFF) != 0; v <<= 1 )
        printf( "%c", IS_FLAG(b, v) ? '*' : ' ' );
}

void DoDump( DWORD cn )
  {
    DWORD  n, i, j;
    for( n = nOff; n < cn; ) {

      for( i = 0; i < nPair; i++ ) {
        printf( "%08X ", fOff+i*nLen );

        for( j = 0; j < nLen; j++ )
          printf( "%02X", buff[n+j*nPair+i] );

        printf( "|" );
        for( j = 0; j < nLen; j++ )
          PByte( buff[n+j*nPair+i] );
        printf( "|\n" );
      }
      if ( nPair > 1 ) printf( "\n" );

      n += nPair*nLen;
      fOff += nPair*nLen;
    }
}

DWORD GetFile( CONSTSTR fnm )
  {
     printf( "Reading from file: %s\n", fnm );
     int f = FIO_OPEN( fnm, O_RDONLY );
     if ( f == -1 ) HAbort( "!open file" );

     DWORD len;

     if ( (m = CTArgGet("fOff")) != NULL )
       fOff = Str2DigitDetect(m,10,0);
      else
       fOff = 0;
     FIO_SEEK( f, fOff, seekBEGIN );
     printf( "Start from: %08X\n", fOff );

     if ( (m=CTArgGet("fLen")) != NULL )
       len = Str2DigitDetect(m,10,0);
      else
       len = sizeof(buff);
     printf( "Dump: %d bytes\n", len );

     for( DWORD n = 0; n < len; ) {
       DWORD rc;

       rc = Min( sizeof(buff), (size_t)len );
       rc -= rc % (nPair*nLen);

       rc = FIO_READ( f, buff, rc );
       if ( !rc )
         break;

       DoDump( rc );
       n    += rc;
     }

     FIO_CLOSE( f );

 return len;
}

void main( int argc,char *argv[] )
  {
    CTArgInit(argc,argv,FALSE);

    if (argc < 2 || CTArgCheck("?") ) {
      printf( "USAGE: %s <usage> [<ops>]\n"
              " <ops>\n"
              "  -nPair=<val>           - number of bytes in char height (%d)\n"
              "  -nLen=<val>            - number of bytes in char width (%d)\n"
              "  -nOff=<val>            - bytes offset (%d)\n"
              "\n"
              "1. PB <bytes>            - print bytes\n"
              "  <FileOptions>\n"
              "\n"
              "2. PB @<filename> <fops> - read and print portin of file\n"
              "  <fops>\n"
              "    -fOff=offset         - read start (%d)\n"
              "    -fLen=length         - read length (%d)\n"
              "",
              FNameOnly(argv[0]),
              nPair, nLen, nOff, fOff, sizeof(buff)
               );
      return;
    }

    if ( (m=CTArgGet("nPair")) != 0 ) nPair = atoi(m); printf( "Pair: %d\n", nPair );
    if ( (m=CTArgGet("nLen")) != 0 ) nLen = atoi(m);   printf( "Len: %d\n", nLen );
    if ( (m=CTArgGet("nOff")) != 0 ) nOff = atoi(m);   printf( "Off: %d\n", nOff );

    DWORD cn;
    m = CTArgGetArg(0);
    if ( *m == '@' )
      GetFile( m+1 );
     else {
      cn = Text2BytesRaw( m, buff, sizeof(buff) );
      printf( "Bytes [%d]:\n", cn );
      DoDump( cn );
    }
}
